package online.zhangwenzhe.common.security.datasource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * Description
 *
 * @author zhangwenzhe
 * @since 2018/8/15 下午4:01
 */

@Service
public class AuthenticationResourceDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 获取所有资源
     *
     * @return
     */
    public List<ResourceVo> getAllResource() {
        String sql = "select * from auth_resource";
        return getResourceBySQL(sql, new Object[]{});
    }

    /**
     * 获取用户可访问的资源
     *
     * @param userId 用户ID
     * @return 可访问资源列表
     */
    public List<ResourceVo> getGrantedResource(Long userId) {
        String sql = "select r.* from auth_user u\n" +
                "join auth_user_role ur on u.id = ur.auth_user_id\n" +
                "join auth_permission p on ur.auth_role_id = p.auth_role_id\n" +
                "join auth_resource r on p.auth_resource_id = r.id\n" +
                "where u.id = ?";
        return getResourceBySQL(sql, new Object[]{userId});
    }

    private List<ResourceVo> getResourceBySQL(String sql, Object[] parm) {
        RowMapper<ResourceVo> mapper = new RowMapper<ResourceVo>() {
            @Override
            public ResourceVo mapRow(ResultSet resultSet, int i) throws SQLException {
                ResourceVo resource = new ResourceVo();
                resource.setId(resultSet.getLong("id"));
                resource.setName(resultSet.getString("name"));
                resource.setIcon(resultSet.getString("icon"));
                resource.setShowInMenu(resultSet.getBoolean("is_show_in_menu"));
                resource.setParentId(resultSet.getLong("parent_id"));
                resource.setUri(resultSet.getString("uri"));
                resource.setMethod(resultSet.getString("method"));
                resource.setDescription(resultSet.getString("description"));
                resource.setDeleted(resultSet.getBoolean("is_deleted"));
                return resource;
            }
        };
        List<ResourceVo> result = jdbcTemplate.query(sql, mapper, parm);
        return result;
    }

    public List<String> getAuthorizedResource(Long userId) {
        String sql = new StringBuilder()
                .append("select res.uri\n")
                .append("from auth_resource res\n")
                .append("  join auth_permission p on res.id = p.auth_resource_id\n")
                .append("  join auth_role role on p.auth_role_id = role.id\n")
                .append("  join auth_user_role ur on role.id = ur.auth_role_id\n")
                .append("where auth_user_id = ?\n").toString();
        RowMapper<String> rowMapper = (resultSet, i) -> resultSet.getString(1);
        List<String> result = jdbcTemplate.query(sql, rowMapper, new Object[]{userId});
        return result;
    }

    /**
     * 获取资源与角色的映射关系
     *
     * @return
     */
    public List<ResourceRoleMapVo> loadResourceRoleMap() {
        List<ResourceRoleMapVo> resourceRoleMapVoList = new ArrayList<>();

        String sql = new StringBuilder()
                .append("select\n")
                .append("  a.uri,\n")
                .append("  a.method,\n")
                .append("  r.id as role_id\n")
                .append("from auth_role r\n")
                .append("  join auth_permission p on r.id = p.auth_role_id\n")
                .append("  join auth_resource a on p.auth_resource_id = a.id\n")
                .append("order by uri;").toString();

        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql);

        // 循环添加url和role的对应关系，并且去重
        while (sqlRowSet.next()) {
            String uri = sqlRowSet.getString("uri");
            String method = sqlRowSet.getString("method");
            String roleId = sqlRowSet.getString("role_id");

            ResourceRoleMapVo mapContained = resourceRoleMapVoList
                    .stream()
                    .filter(x -> method.equals(x.getMethod()) && uri.equals(x.getUri()))
                    .findFirst()
                    .orElse(null);

            if (mapContained == null) {
                ResourceRoleMapVo resourceRoleMapVo = new ResourceRoleMapVo();
                resourceRoleMapVo.setUri(uri);
                resourceRoleMapVo.setMethod(method);
                resourceRoleMapVo.getRoleIdList().add(roleId);
                resourceRoleMapVoList.add(resourceRoleMapVo);
            } else {
                if (!mapContained.getRoleIdList().contains(roleId)) {
                    mapContained.getRoleIdList().add(roleId);
                }
            }
        }

        return resourceRoleMapVoList;
    }

    public List<String> getRoleByUser(Long userId) {
        String sql = "select distinct auth_role_id from auth_user_role where auth_user_id = ?";

        RowMapper<String> rowMapper = (resultSet, i) -> resultSet.getString(1);

        List<String> roles = jdbcTemplate.query(sql, rowMapper, new Object[]{userId});

        return roles;
    }


}
